package com.example.amusic.service

import android.content.Context
import android.content.Intent
import android.media.audiofx.AudioEffect
import android.os.Bundle
import android.util.Log
import androidx.annotation.OptIn
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.CommandButton
import androidx.media3.session.MediaSession
import androidx.media3.session.SessionCommand
import com.example.amusic.R
import com.example.amusic.utils.MediaSessionConstants
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class CustomMediaServiceHandler(
    val player: ExoPlayer,
    private val mediaSession: MediaSession,
    customMediaSessionCallback: CustomMediaSessionCallback,
    private val context: Context,
    var coroutineScope: LifecycleCoroutineScope,
) : Player.Listener {

    private var _nowPlaying = MutableStateFlow(player.currentMediaItem)
    val nowPlaying = _nowPlaying.asSharedFlow()

    private var _musicMediaState = MutableStateFlow<MusicMediaState>(MusicMediaState.Initial)
    val musicMediaState = _musicMediaState.asStateFlow()


    private var job: Job? = null
    private var updateNotificationJob: Job? = null

    init {
        player.addListener(this)
        job = Job()
        updateNotificationJob = Job()
        _nowPlaying.value = player.currentMediaItem
        customMediaSessionCallback.apply {
            toggleLike = ::toggleLike
            toggleRepeat = ::toggleRepeat
        }
    }

    suspend fun onPlayerEvent(playerEvent: PlayerEvent) {
        when(playerEvent){
            is PlayerEvent.PlayAll -> {
                player.stop()
                player.setMediaItems(playerEvent.songList)
                player.play()
            }
            PlayerEvent.PlayPause -> TODO()
        }
    }

    override fun onPlaybackStateChanged(playbackState: Int) {
        when (playbackState) {
            ExoPlayer.STATE_IDLE -> _musicMediaState.value = MusicMediaState.Initial
            ExoPlayer.STATE_ENDED -> _musicMediaState.value = MusicMediaState.Ended
            ExoPlayer.STATE_BUFFERING -> _musicMediaState.value =
                MusicMediaState.Buffering(player.currentPosition)

            ExoPlayer.STATE_READY -> _musicMediaState.value = MusicMediaState.Ready(player.duration)
        }
    }

    override fun onIsPlayingChanged(isPlaying: Boolean) {
        _musicMediaState.value = MusicMediaState.Playing(isPlaying = isPlaying)
        if (isPlaying) {
            coroutineScope.launch(Dispatchers.Main) {
                startProgressUpdate()
            }
        } else {
            stopProgressUpdate()
        }
    }

    override fun onIsLoadingChanged(isLoading: Boolean) {
        super.onIsLoadingChanged(isLoading)
        _musicMediaState.value = MusicMediaState.Loading(player.bufferedPercentage, player.duration)
        if (isLoading) {
            coroutineScope.launch(Dispatchers.Main) {
                startBufferedUpdate()
            }
        } else {
            stopBufferedUpdate()
        }
    }

    private suspend fun startBufferedUpdate() =
        job.run {
            while (true) {
                delay(500)
                _musicMediaState.value =
                    MusicMediaState.Loading(player.bufferedPercentage, player.duration)
            }
        }

    private fun stopBufferedUpdate() {
        job?.cancel()
        _musicMediaState.value =
            MusicMediaState.Loading(player.bufferedPercentage, player.duration)
    }

    override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
        Log.e(
            "TAG",
            "onMediaItemTransition: Current Position: ${player.currentPosition}  Media Item: ${mediaItem?.mediaMetadata?.title}",
        )
        _nowPlaying.value = mediaItem
        updateNotification()
    }

    private suspend fun startProgressUpdate() = job.run {
        while (true) {
            delay(100)
            _musicMediaState.value = MusicMediaState.Progress(player.currentPosition)
        }
    }

    private fun stopProgressUpdate() {
        job?.cancel()
        _musicMediaState.value = MusicMediaState.Playing(isPlaying = false)
    }

    fun getProgress(): Long {
        return player.currentPosition
    }

    fun release() {
        player.stop()
        player.playWhenReady = false
        player.removeListener(this)
        sendCloseEqualizerIntent()
        if (updateNotificationJob?.isActive == true) {
            updateNotificationJob?.cancel()
            updateNotificationJob = null
        }
        if (job?.isActive == true) {
            job?.cancel()
            job = null
        }
    }

    @OptIn(UnstableApi::class)
    private fun sendCloseEqualizerIntent() {
        context.sendBroadcast(
            Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION).apply {
                putExtra(AudioEffect.EXTRA_AUDIO_SESSION, player.audioSessionId)
            },
        )
    }

    private fun toggleLike() {
        updateNotification()
    }

    private fun toggleRepeat() {
        updateNotification()
    }

    private fun updateNotification() {
        updateNotificationJob?.cancel()
        updateNotificationJob =
            coroutineScope.launch {
                //查询状态
                mediaSession.setCustomLayout(
                    listOf(
                        CommandButton.Builder()
                            .setDisplayName("喜欢")
                            .setIconResId(R.drawable.baseline_favorite_24)
                            .setSessionCommand(SessionCommand(MediaSessionConstants.LIKE, Bundle()))
                            .build(),

                        CommandButton.Builder()
                            .setDisplayName("模式")
                            .setIconResId(R.drawable.baseline_repeat_24)
                            .setSessionCommand(SessionCommand(MediaSessionConstants.LIKE, Bundle()))
                            .build(),
                    )
                )
            }
    }
}


sealed class MusicMediaState {
    data object Initial : MusicMediaState()
    data object Ended : MusicMediaState()
    data class Ready(val duration: Long) : MusicMediaState()
    data class Loading(val bufferedPercentage: Int, val duration: Long) : MusicMediaState()
    data class Progress(val progress: Long) : MusicMediaState()
    data class Buffering(val position: Long) : MusicMediaState()
    data class Playing(val isPlaying: Boolean) : MusicMediaState()
}


sealed class PlayerEvent {
    data object PlayPause : PlayerEvent()
    data class PlayAll(val songList: List<MediaItem>) : PlayerEvent()
}












